package oralExamSchedulingSystemTest;

import oralExamSchedulingSystem.IO;
import oralExamSchedulingSystem.SubjectTimeTable;

import junit.framework.*;
import org.junit.Test;
import org.junit.After;
import org.junit.Before;

import test.entityTest.TestClass;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

// TODO: Auto-generated Javadoc
/**
 * The Class TestIO.
 */
public class TestIO extends TestCase {

	/** The io. */
	private IO io;

	/** The received input. */
	private String receivedInput;
	
	/** The actual output. */
	private String[] actualOutput;
	
	/** The actual input. */
	private String actualInput;

	/** The out. */
	private ByteArrayOutputStream out;
	
	/** The in. */
	private InputStream in;

	/**
	 * Instantiates a new test io.
	 *
	 * @param name the name
	 */
	public TestIO(String name) {
		super(name);
	}

	/* (non-Javadoc)
	 * @see junit.framework.TestCase#setUp()
	 */
	@Before
	public void setUp() throws Exception {

	}

	/* (non-Javadoc)
	 * @see junit.framework.TestCase#tearDown()
	 */
	@After
	public void tearDown() throws Exception {
	}

	/**
	 * Sets the in out stream.
	 */
	private void setInOutStream() {
		// set a test output
		out = new ByteArrayOutputStream();
		System.setOut(new PrintStream(out));

		// set a test input
		in = new ByteArrayInputStream(actualInput.getBytes());
		System.setIn(in);

	}

	/**
	 * Gets the screen result.
	 *
	 * @return the screen result
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	private void getScreenResult() throws IOException {

		// get the actual screen output
		out.flush();
		String whatWasPrinted = new String(out.toByteArray());
		actualOutput = whatWasPrinted.split(System
				.getProperty("line.separator"));

	}

	/**
	 * Test get reporting room number_404.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetReportingRoomNumber_404() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Reporting Room Number: ";
		String expectedInput = "404";
		actualInput = "404";

		setInOutStream();
		// get the actual input
		receivedInput = io.getReportingRoomNumber();
		getScreenResult();
		// test the screen number of line
		assertEquals(actualOutput.length, 1);
		// test the screen output
		assertEquals(expectedOutput, actualOutput[0]);
		// test the input
		assertEquals(expectedInput, receivedInput);
	}

	/**
	 * Test get reporting room number_404_ a.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetReportingRoomNumber_404_A() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Reporting Room Number: ";

		String expectedInput = "404 A";
		actualInput = "404 A";
		setInOutStream();
		// get the actual input
		receivedInput = io.getReportingRoomNumber();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);

	}

	/**
	 * Test get academic year_2012.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetAcademicYear_2012() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Academic Year: ";
		String expectedInput = "2012";
		actualInput = "2012";

		setInOutStream();

		receivedInput = io.getAcademicYear();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}

	/**
	 * Test get semester_1.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetSemester_1() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Semester([1]-First Term   [2]-Second Term   [3]-Mock Exam): ";
		String expectedInput = "First Term";
		actualInput = "1";

		setInOutStream();
		receivedInput = io.getSemester();
		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);

	}

	/**
	 * Test get semester_2.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetSemester_2() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Semester([1]-First Term   [2]-Second Term   [3]-Mock Exam): ";
		String expectedInput = "Second Term";
		actualInput = "2";

		setInOutStream();
		receivedInput = io.getSemester();
		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);

	}
	
	/**
	 * Test get semester_3.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetSemester_3() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Semester([1]-First Term   [2]-Second Term   [3]-Mock Exam): ";
		String expectedInput = "Mock Exam";
		actualInput = "3";

		setInOutStream();
		receivedInput = io.getSemester();
		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);

	}
	
	/**
	 * Test get7 room numbers_402_403_405_406_407_408_411.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGet7RoomNumbers_402_403_405_406_407_408_411()
			throws IOException {
		io = new IO();

		String expectedOutput1 = "Input the Room Numbers: ";
		ArrayList<String> expectedArrayList = new ArrayList<String>(
				Arrays.asList("402", "403", "405", "406", "407", "408", "411"));

		String actualInput = "402 403 405 406 407 408 411";

		// set a test output
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		System.setOut(new PrintStream(out));

		// set a test input
		InputStream in = new ByteArrayInputStream(actualInput.getBytes());
		System.setIn(in);

		// get the actual input
		ArrayList<String> receivedArrayList = io.getRoomNumbers(7);

		// get the actual screen output
		out.flush();
		String whatWasPrinted = new String(out.toByteArray());
		String[] linesOfOutput = whatWasPrinted.split(System
				.getProperty("line.separator"));

		// test the screen number of line
		assertEquals(linesOfOutput.length, 1);

		// test the screen output
		assertEquals(expectedOutput1, linesOfOutput[0]);
		//assertEquals(expectedOutput2, linesOfOutput[1]);

		// test the input
		assertEquals(true, expectedArrayList.equals(receivedArrayList));

	}

	/**
	 * Test get start time_0830.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetStartTime_0830() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Starting Time(hh:mm): ";
		String expectedInput = "08:30";
		actualInput = "08:30";

		setInOutStream();

		receivedInput = io.getStartingTime();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}

	/**
	 * Test export schedule.
	 */
	@Test
	public void testExportSchedule() {
		// io = new IO();
		// SubjectTimeTable stt = new SubjectTimeTable();
		// final File dir = new File("tmp");
		// final File expected = new File("xyz.txt");
		// final File output = new File(dir, "xyz.txt");
		// TestClass.xyz(output);
		// Assert.assertEquals(FileUtils.readLines(expected),
		// FileUtils.readLines(output));
	}
	
	/**
	 * Test closing msg.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testClosingMsg() throws IOException {
		io = new IO();
		
		String expectedOutput = "Thank you for using our system!";
	
		actualInput="";
		setInOutStream();
		io.closingMsg();
		getScreenResult();
		
		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
	}


	/**
	 * Test get group size.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetGroupSize() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Group Size(>=3): ";
		String expectedInput = "4";
		actualInput = "4";

		setInOutStream();

		receivedInput = Integer.toString(io.getGroupSize());

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}

	/**
	 * Test get duration.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetDuration() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Duration in minutes(5-30): ";
		String expectedInput = "10";
		actualInput = "10";

		setInOutStream();

		receivedInput = Integer.toString(io.getDuration());

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}

	/**
	 * Test get number of room.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetNumberOfRoom() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Number of Rooms: ";
		String expectedInput = "2";
		actualInput = "2";

		setInOutStream();

		receivedInput = Integer.toString(io.getNumberOfRoom());

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get date in big month.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetDate1() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Exam Date(DDMMYYYY): ";
		String expectedInput = "01/01/2013(DD/MM/YYYY)";
		actualInput = "01012013";

		setInOutStream();

		receivedInput = io.getDate();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get date with a date in non-leap year.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetDate2() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Exam Date(DDMMYYYY): ";
		String expectedInput = "28/02/2013(DD/MM/YYYY)";
		actualInput = "28022013";

		setInOutStream();

		receivedInput = io.getDate();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get date with a date in leap year.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetDate3() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Exam Date(DDMMYYYY): ";
		String expectedInput = "29/02/2012(DD/MM/YYYY)";
		actualInput = "29022012";

		setInOutStream();

		receivedInput = io.getDate();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
		
	/**
	 * Test get level.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetLevel1() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Level(1-6): ";
		String expectedInput = "Form 1";
		actualInput = "1";

		setInOutStream();

		receivedInput = io.getLevel();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get level.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetLevel2() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Level(1-6): ";
		String expectedInput = "Form 2";
		actualInput = "2";

		setInOutStream();

		receivedInput = io.getLevel();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get level.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetLevel3() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Level(1-6): ";
		String expectedInput = "Form 3";
		actualInput = "3";

		setInOutStream();

		receivedInput = io.getLevel();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get level.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetLevel4() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Level(1-6): ";
		String expectedInput = "Form 4";
		actualInput = "4";

		setInOutStream();

		receivedInput = io.getLevel();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get level.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetLevel5() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Level(1-6): ";
		String expectedInput = "Form 5";
		actualInput = "5";

		setInOutStream();

		receivedInput = io.getLevel();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get level.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetLevel6() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Level(1-6): ";
		String expectedInput = "Form 6";
		actualInput = "6";

		setInOutStream();

		receivedInput = io.getLevel();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get number of subjects.
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetNumberOfSubjects1() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Number of Subjects(1-2): ";
		String expectedInput = "1";
		actualInput = "1";

		setInOutStream();

		receivedInput = Integer.toString(io.getNumberOfSubjects());

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get subject name
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetSubjectName1() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Subject Name([1]-Chinese Language   [2]-English Language): ";
		String expectedInput = "Chinese Language";
		actualInput = "1";

		setInOutStream();

		receivedInput = io.getSubjectName();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
	/**
	 * Test get subject name
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@Test
	public void testGetSubjectName2() throws IOException {
		io = new IO();
		String expectedOutput = "Input the Subject Name([1]-Chinese Language   [2]-English Language): ";
		String expectedInput = "English Language";
		actualInput = "2";

		setInOutStream();

		receivedInput = io.getSubjectName();

		getScreenResult();

		assertEquals(actualOutput.length, 1);
		assertEquals(expectedOutput, actualOutput[0]);
		assertEquals(expectedInput, receivedInput);
	}
	
}